package com.ruoyi.controller;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.entity.JrFile;
import com.ruoyi.entity.JrSecuritys;
import com.ruoyi.entity.vo.FileUploadVO;
import com.ruoyi.server.MinioService;
import com.ruoyi.service.FilesService;
import com.ruoyi.util.MinioUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@Api(tags = "FilesController   api")
@Slf4j
@RequestMapping("/api/files")
public class FilesController extends BaseController {
    @Autowired
    private FilesService filesService;

    @Autowired
    private MinioService minioService;

    @Value("${minio.bucket-name}")
    private String bucketName;

    @Autowired
    @Qualifier("customMinioUtil")  // 指定Bean名称
    private MinioUtil minioUtil;

    @ApiOperation("OnlyOffice 编辑回调")
    @PostMapping("/callback")
    public ResponseEntity<String> callback(
            @RequestBody JSONObject request
    ) {
        log.info("接收到回调请求：{}", request.toJSONString());
        try {
            int status = request.getIntValue("status");
            String fileKey = request.getString("key");

            // 处理保存逻辑
            if (status == 2) {
                return handleFileSave(request, fileKey);
            } else {
                // 处理其他状态码（如 6: 正在编辑，3: 已关闭）
                log.info("处理状态码: {}", status);
                return ResponseEntity.ok("{\"error\": 0}");
            }
        } catch (Exception e) {
            log.error("回调处理失败", e);
            return ResponseEntity.ok("{\"error\": 1, \"message\": \"回调处理失败: " + e.getMessage() + "\"}");
        }
    }
    // 处理文件保存逻辑
    private ResponseEntity<String> handleFileSave(JSONObject request, String fileKey) {
        try {
            // 从 key 中解析 bucketName 和 fileName（或从前端传递的 metadata 中获取）
            String[] keyParts = fileKey.split(":");
            String bucketName = keyParts[0];
            String fullFileName = keyParts[1];
            // 提取原文件名（去掉末尾的 "_时间戳"）
            String originalFileName = fullFileName.substring(0, fullFileName.lastIndexOf("_"));

            // 获取 OnlyOffice 提供的临时下载链接（状态码为 2 时才有）
            String downloadUrl = request.getString("url");

            log.info("下载链接: {}", downloadUrl);

            // 下载文件并保存到 MinIO
            boolean saveResult = downloadAndSaveToMinio(downloadUrl, bucketName, originalFileName);

            return saveResult
                    ? ResponseEntity.ok("{\"error\": 0}")
                    : ResponseEntity.ok("{\"error\": 1, \"message\": \"MinIO 保存失败\"}");
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.ok("{\"error\": 1, \"message\": \"保存文件失败: " + e.getMessage() + "\"}");
        }
    }
    // 下载文件并保存到 MinIO（二进制）
    private boolean downloadAndSaveToMinio(String downloadUrl, String bucketName, String fileName) {
        try {
            log.info("尝试下载文件: {}", downloadUrl);
            RestTemplate restTemplate = new RestTemplate();
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            factory.setConnectTimeout(5000);
            factory.setReadTimeout(10000);
            restTemplate.setRequestFactory(factory);

            // 下载二进制文件（捕获下载失败的具体错误）
            byte[] fileBytes;
            try {
                fileBytes = restTemplate.getForObject(downloadUrl, byte[].class);
            } catch (Exception e) {
                throw new RuntimeException("下载文件失败: " + e.getMessage(), e);
            }

            if (fileBytes == null || fileBytes.length == 0) {
                throw new RuntimeException("下载的文件内容为空");
            }

            // 保存到 MinIO
            log.info("保存到 MinIO: bucket={}, file={}, 大小={}字节", bucketName, fileName, fileBytes.length);
            minioService.saveFile(bucketName, fileName, fileBytes);
            return true;
        } catch (Exception e) {
            log.error("下载并保存文件失败", e);
            throw new RuntimeException("下载并保存文件失败", e);
        }
    }

    @PutMapping("/{fileId}/renameFile")
    public AjaxResult renameFile(@PathVariable Long fileId, @RequestBody Map<String, String> request) {
        String newName = request.get("newName");
        if (StringUtils.isBlank(newName)) {
            return AjaxResult.error("新文件名不能为空");
        }

        try {
            int result = filesService.renameFile(fileId, newName);
            return result > 0 ? AjaxResult.success() : AjaxResult.error("重命名失败");
        } catch (ServiceException e) {
            return AjaxResult.error(e.getMessage());
        }
    }

    @DeleteMapping("/{fileId}")
    public AjaxResult deleteFile(@PathVariable Long fileId) {
        System.out.println("FilesController文件删除：" + fileId);
        return toAjax(filesService.deleteFile(fileId));
    }

    @ApiOperation("密级下拉框")
    @GetMapping("/levels")
    public List<JrSecuritys> getSecurityLevels() {
        List<JrSecuritys> files = filesService.getFilesByCurrentUserSecurity();
        System.out.println("下拉------------------------ ： " + files);
        return files;
    }


    @ApiOperation("上传文件2")
    @PostMapping(value = "/uploadNew", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public AjaxResult uploadFile(@RequestPart("files") MultipartFile[] files, // 必须使用@RequestPart
                                 @RequestPart("dto") FileUploadVO dto) {
        System.out.println(">>>> 上传文件2接口被调用 <<<<");
        dto.setFolderId(dto.getFolderId());
        dto.setSecurity(dto.getSecurity());
        dto.setHandleType(dto.getHandleType());
        return filesService.uploadFile(files, dto);
    }


    //查看文件是否存在
    private String getFileExtension(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
    }

    //查看文件类型
    private String getDocumentType(String fileName) {
        String ext = getFileExtension(fileName);
        switch (ext) {
            case "doc":
            case "docx":
                return "text";
            case "xls":
            case "xlsx":
                return "spreadsheet";
            case "ppt":
            case "pptx":
                return "presentation";
            default:
                return "text";
        }
    }


    private String getTokenFromRequest() {
        // 从请求参数中获取 Token
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request.getParameter("token");
    }

    @ApiOperation("编辑并保存MinIO文件内容")
    @PostMapping("/editAndSave")
    public AjaxResult editAndSaveFile(@RequestBody Map<String, String> params) {
        String bucketName = params.get("bucketName");
        String fileName = params.get("fileName");
        String content = params.get("content");
        if (StringUtils.isAnyBlank(bucketName, fileName, content)) {
            return AjaxResult.error("参数不能为空");
        }
        boolean result = minioService.saveContent(bucketName, fileName, content);
        return result ? AjaxResult.success("保存成功") : AjaxResult.error("保存失败");
    }

    @ApiOperation("下载MinIO文件")
    @GetMapping("/download")
    public void downloadMinioFile(@RequestParam String bucketName, @RequestParam String fileName, HttpServletResponse response) {
        try (InputStream is = minioService.getFile(bucketName, fileName)) {
            if (is == null) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.getWriter().write("File not found");
                return;
            }
            // 设置响应头以触发浏览器下载
            response.setContentType("application/octet-stream");
            String encodedFileName = java.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");

            // 将文件内容复制到响应输出流
            IOUtils.copy(is, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error("文件下载失败: bucket={}, file={}", bucketName, fileName, e);
            throw new RuntimeException("文件下载失败", e);
        }
    }

    @ApiOperation("提取并查看 .docx 文件文本内容")
    @GetMapping("/extractText")
    public AjaxResult extractText(@RequestParam String bucketName, @RequestParam String fileName) {
        if (!fileName.toLowerCase().endsWith(".docx")) {
            return AjaxResult.error("此接口仅支持 .docx 文件");
        }

        try (InputStream is = minioService.getFile(bucketName, fileName)) {
            if (is == null) {
                return AjaxResult.error("文件不存在");
            }

            XWPFDocument document = new XWPFDocument(is);
            XWPFWordExtractor extractor = new XWPFWordExtractor(document);
            String text = extractor.getText();
            extractor.close();

            return AjaxResult.success("提取成功", text);

        } catch (Exception e) {
            log.error("提取文件文本失败: bucket={}, file={}", bucketName, fileName, e);
            return AjaxResult.error("提取失败: " + e.getMessage());
        }
    }

}
